﻿using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using System;
using System.Collections.Generic;

namespace ArtMath.PointCollection
{
    [Serializable]
    public class StraightLine : ContinuityPoint
    {
        public PointD Location;
        public double Slope;
        public StraightLine()
        {

        }
        public StraightLine(PointD location, double k)
        {
            Location = location;
            Slope = k;
        }
        //public StraightLine(params PointD[] exceptPoints)
        //{
        //    Exceptions = new HashSet<PointCollectionBase>() { new DiscontinuityPoint(exceptPoints) };
        //}
        public override bool Contains(PointD pt)
        {
            return pt.DistanceTo(Location, Slope).AlmostEqual(0) && AfterContains(pt);
        }

        public override PointD? GetNearestPoint(PointD pt)
        {
            return pt.GetProjectivePoint(Location, Slope);
        }
        public override PointD SlideDestination(PointD currentLocation, double length, out bool reverse)
        {
            reverse = false;
            if (length > 0)
            {
                return currentLocation.Offset(Utility.GetSlopeAngle(Slope), length);
            }
            else
            {
                return currentLocation.Offset(Utility.GetSlopeAngle(Slope) + Math.PI, -length);
            }
        }
        protected override PointCollectionBase Intersect(PointCollectionBase collection)
        {
            HashSet<PointD> set = new HashSet<PointD>();
            StraightLine sl = collection as StraightLine;
            if (sl != null)
            {
                set.Add(Utility.GetCrossPoint(Location, Slope, sl.Location, sl.Slope));
            }
            else
            {
                double[] abc = Location.GetABC(Slope);
                PartialCircle arc = collection as PartialCircle;
                if (arc != null)
                {
                    set.AddRange(CurveIntersection.StraightLineArcIntersection(abc[0], abc[1], abc[2], arc.Center, arc.Radius, arc.Start, arc.Sweep));
                }
                else
                {
                    Circle cir = collection as Circle;
                    if (cir != null)
                    {
                        set.AddRange(CurveIntersection.StraightLineCircleIntersection(abc[0], abc[1], abc[2], cir.Center, cir.Radius));
                    }
                    else
                    {
                        Ellipse oval = collection as Ellipse;
                        if (oval != null)
                        {
                            set.AddRange(CurveIntersection.StraightLineEllipseIntersection(abc[0], abc[1], abc[2], oval.Center, oval.LongAxisHalfLength, oval.ShortAxisHalfLength, oval.RotateAngle));
                        }
                        else
                        {
                            Hyperbola hyp = collection as Hyperbola;
                            if (hyp != null)
                            {
                                set.AddRange(CurveIntersection.StraightLineHyperbolaIntersection(abc[0], abc[1], abc[2], hyp.Center, hyp.RealAxisHalfLength, hyp.ImaginaryAxisHalfLength, hyp.RotateAngle));
                            }
                            else
                            {
                                Parabola para = collection as Parabola;
                                if (para != null)
                                {
                                    set.AddRange(CurveIntersection.StraightLineParabolaIntersection(abc[0], abc[1], abc[2], para.Center, para.FocusDirectrixDistance, para.RotateAngle));
                                }
                                else
                                {
                                    CurveDescribable cd = collection as CurveDescribable;
                                    if (cd != null && cd.Curves != null)
                                    {
                                        foreach (Curve item in cd.Curves)
                                        {
                                            set.AddRange(CurveIntersection.StraightLineCurveIntersection(Location, Slope, item, item.IsClosed));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (set.Count == 0) return Empty.Instance;
            return AfterIntersect(collection.AfterIntersect(new DiscontinuityPoint(set)));
        }
    }
}
